文章列表的路由已經存在 Resource 裡,只要再加一個草稿列表的路由,而且一定要放在 ShowPost 上面:
routes/web.php
// Posts
...
Route::get('posts/drafts', 'Post\PostController@drafts');
Route::get('posts/{post}', 'Post\ShowPost');
然後是文章列表和草稿列表的 Controller 部分:
app/Http/Controllers/Post/PostController.php
public function index()
{
$posts = $this->user()
->posts()
->where('published', true)
->latest()
->get();
return Inertia::render('Post/List', [
'type' => 'published',
'typeText' => '文章',
'posts' => PostPresenter::collection($posts)
->preset('list')
->get(),
]);
}
public function drafts()
{
$posts = $this->user()
->posts()
->where('published', false)
->latest()
->get();
return Inertia::render('Post/List', [
'type' => 'drafts',
'typeText' => '草稿',
'posts' => PostPresenter::collection($posts)
->preset('list')
->get(),
]);
}
還有屬於列表的 preset,裡面要放文章作者,需要的欄位不用那麼多,可以用 only()
指定:
app/Presenters/PostPresenter.php
public function presetList()
{
return $this->with(fn (Post $post) => [
'author' => fn () => UserPresenter::make($post->author)
->only('id', 'name', 'avatar')
->get(),
]);
}
兩個列表是共用同一個列表頁面,只差會放不同的文章集合:
resources/js/Pages/Post/List.vue
<template>
<div class="py-6 md:py-8">
<alert v-if="$page.flash.success" class="shadow mb-6">{{ $page.flash.success }}</alert>
<div class="card card-main">
<div>
<div class="flex justify-between items-center">
<h2 class="text-3xl">我的{{ typeText }}</h2>
<div>
<inertia-link href="/posts/create" class="link">
<icon icon="heroicons-outline:pencil" />
撰寫文章
</inertia-link>
</div>
</div>
<hr class="mt-4">
<tabs class="mt-4" :active="type">
<tab name="published" url="/posts">已發布</tab>
<tab name="drafts" url="/posts/drafts">草稿</tab>
</tabs>
</div>
<div class="mt-6">
<post-list :posts="posts" hide-author :empty="`目前沒有${typeText}`" />
</div>
</div>
</div>
</template>
<script>
import AppLayout from '@/Layouts/AppLayout'
import Alert from '@/Components/Alert'
import Tabs from '@/Components/Tabs'
import Tab from '@/Components/Tab'
import PostList from '@/Lightning/PostList'
export default {
layout: AppLayout,
metaInfo() {
return {
title: `我的${this.typeText}`
}
},
components: {
Alert,
Tabs,
Tab,
PostList
},
props: {
type: String,
typeText: String,
posts: Array
}
}
</script>
還有要做使用到的組件們,首先是真正的文章列表組件,只要是文章列表都可以用這個組件渲染:
resources/js/Lightning/PostList.vue
<template>
<div>
<ul v-if="posts.length" class="divide-y -my-6">
<li v-for="post in posts" class="py-6">
<h2>
<inertia-link :href="`/posts/${post.id}`" class="text-xl font-medium hover:text-purple-500 transition-colors duration-100">{{ post.title }}</inertia-link>
</h2>
<div class="text-gray-500 font-light mt-1">{{ post.description }}</div>
<div class="flex items-center space-x-4 text-gray-500 text-sm font-light" :class="hideAuthor ? 'mt-1' : 'mt-3'">
<inertia-link v-if="!hideAuthor" :href="`/user/${post.author.id}`" class="inline-flex items-center hover:text-purple-500 font-normal">
<img :src="post.author.avatar" class="w-6 h-6 rounded-full">
<span class="ml-2">{{ post.author.name }}</span>
</inertia-link>
<div>
<icon class="w-4 h-4 text-purple-500" icon="heroicons-outline:clock" />
{{ post.created_ago }}
</div>
<slot name="info-after" :post="post" />
</div>
</li>
</ul>
<div v-else class="text-center text-gray-400 mt-8 mb-4">{{ empty }}</div>
</div>
</template>
<script>
export default {
props: {
posts: {
type: Array,
required: true
},
hideAuthor: {
type: Boolean,
default: false
},
empty: {
type: String,
default: '目前沒有文章'
}
}
}
</script>
再來是一組簡易的 Tab 組件:
resources/js/Components/Tabs.vue
<template>
<div class="flex space-x-2">
<slot />
</div>
</template>
<script>
export default {
props: {
active: String
}
}
</script>
resources/js/Components/Tab.vue
<template>
<div v-if="name === active" class="tab tab-active">
<slot />
</div>
<inertia-link v-else :href="url" class="tab tab-link">
<slot />
</inertia-link>
</template>
<script>
export default {
props: {
name: {
type: String,
required: true
},
url: String
},
computed: {
active() {
return this.$parent.$options._componentTag === 'tabs'
? this.$parent.active
: null
}
}
}
</script>
Tab 組件的樣式:
resources/css/components.css
/* Tab */
.tab {
@apply px-2 py-1 text-sm font-light rounded select-none;
}
.tab-link {
@apply text-purple-500 transition-colors duration-100;
&:hover {
@apply text-purple-700;
}
}
.tab-active {
@apply bg-purple-100 text-purple-700;
}
然後就可以看到列表頁面,還可以切換草稿頁面:
列表做好了,但如果文章多了起來,頁面就會很長,載入會很久,因此,下回將要來做列表分頁了。
Lightning 範例程式碼:https://github.com/ycs77/lightning